using AgentFrameworkDemo.Models;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Net.Http.Json;
using System.Text.Json;
using ToolParameter = AgentFrameworkDemo.Models.ToolParameter;

namespace AgentFrameworkDemo.Services;

/// <summary>
/// MCP服务器工具执行器
/// 通过MCP协议与外部服务器通信以使用工具
/// </summary>
public class McpToolExecutor : IToolExecutor
{
    private readonly ILogger<McpToolExecutor> _logger;
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly IConfiguration _configuration;
    private readonly Dictionary<string, McpServerConfig> _mcpServers;
    private readonly Dictionary<string, ToolDefinition> _mcpTools;

    public ToolType ToolType => ToolType.McpServer;

    public McpToolExecutor(
        ILogger<McpToolExecutor> logger,
        IHttpClientFactory httpClientFactory,
        IConfiguration configuration)
    {
        _logger = logger;
        _httpClientFactory = httpClientFactory;
        _configuration = configuration;
        _mcpServers = new Dictionary<string, McpServerConfig>();
        _mcpTools = new Dictionary<string, ToolDefinition>();

        InitializeMcpServers();
    }

    public async Task<List<ToolDefinition>> GetAvailableToolsAsync(string? agentId = null)
    {
        await RefreshMcpToolsAsync();
        return _mcpTools.Values.ToList();
    }

    public async Task<ToolExecutionResult> ExecuteToolAsync(ToolExecutionRequest request)
    {
        var startTime = DateTime.UtcNow;

        try
        {
            _logger.LogInformation("Executing MCP tool: {ToolId}", request.ToolId);

            if (!_mcpTools.TryGetValue(request.ToolId, out var toolDef))
            {
                return new ToolExecutionResult
                {
                    Success = false,
                    ErrorMessage = $"MCP tool not found: {request.ToolId}",
                    ToolId = request.ToolId,
                    ToolName = "Unknown",
                    ExecutionTime = DateTime.UtcNow - startTime,
                    ToolType = ToolType.McpServer
                };
            }

            // 验证参数
            var (isValid, errors) = await ValidateParametersAsync(request.ToolId, request.Parameters);
            if (!isValid)
            {
                return new ToolExecutionResult
                {
                    Success = false,
                    ErrorMessage = $"Parameter validation failed: {string.Join(", ", errors)}",
                    ToolId = request.ToolId,
                    ToolName = toolDef.Name,
                    ExecutionTime = DateTime.UtcNow - startTime,
                    ToolType = ToolType.McpServer
                };
            }

            // 获取服务器配置
            var serverId = toolDef.Configuration.GetValueOrDefault("serverId")?.ToString();
            if (string.IsNullOrEmpty(serverId) || !_mcpServers.TryGetValue(serverId, out var serverConfig))
            {
                return new ToolExecutionResult
                {
                    Success = false,
                    ErrorMessage = $"MCP server not found for tool: {request.ToolId}",
                    ToolId = request.ToolId,
                    ToolName = toolDef.Name,
                    ExecutionTime = DateTime.UtcNow - startTime,
                    ToolType = ToolType.McpServer
                };
            }

            // 执行MCP工具调用
            var result = await CallMcpToolAsync(serverConfig, toolDef, request);

            return new ToolExecutionResult
            {
                Success = result.Success,
                Result = result.Data,
                ErrorMessage = result.Error,
                ToolId = request.ToolId,
                ToolName = toolDef.Name,
                ExecutionTime = DateTime.UtcNow - startTime,
                ToolType = ToolType.McpServer,
                Metadata = new Dictionary<string, object>
                {
                    ["serverId"] = serverId,
                    ["serverName"] = serverConfig.Name,
                    ["agentId"] = request.AgentId,
                    ["sessionId"] = request.SessionId,
                    ["parameters"] = request.Parameters
                }
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to execute MCP tool: {ToolId}", request.ToolId);

            return new ToolExecutionResult
            {
                Success = false,
                ErrorMessage = ex.Message,
                ToolId = request.ToolId,
                ToolName = "MCP Tool",
                ExecutionTime = DateTime.UtcNow - startTime,
                ToolType = ToolType.McpServer
            };
        }
    }

    public async Task<(bool isValid, List<string> errors)> ValidateParametersAsync(string toolId, Dictionary<string, object> parameters)
    {
        var errors = new List<string>();

        if (!_mcpTools.TryGetValue(toolId, out var toolDef))
        {
            errors.Add($"MCP tool not found: {toolId}");
            return (false, errors);
        }

        // 检查必需参数
        foreach (var param in toolDef.Parameters.Where(p => p.Value.Required))
        {
            if (!parameters.ContainsKey(param.Key) || parameters[param.Key] == null)
            {
                errors.Add($"Required parameter missing: {param.Key}");
            }
        }

        // 基本类型验证
        foreach (var param in parameters)
        {
            if (toolDef.Parameters.TryGetValue(param.Key, out var paramDef))
            {
                if (!ValidateParameterType(param.Value, paramDef.Type))
                {
                    errors.Add($"Invalid parameter type for {param.Key}: expected {paramDef.Type}");
                }
            }
        }

        await Task.CompletedTask;
        return (errors.Count == 0, errors);
    }

    public async Task<bool> IsToolAvailableAsync(string toolId)
    {
        await RefreshMcpToolsAsync();
        return _mcpTools.ContainsKey(toolId);
    }

    public async Task<ToolDefinition?> GetToolDefinitionAsync(string toolId)
    {
        await RefreshMcpToolsAsync();
        return _mcpTools.TryGetValue(toolId, out var toolDef) ? toolDef : null;
    }

    private void InitializeMcpServers()
    {
        try
        {
            var mcpSection = _configuration.GetSection("AgentFramework:McpServers");
            if (mcpSection.Exists())
            {
                foreach (var serverSection in mcpSection.GetChildren())
                {
                    var serverConfig = new McpServerConfig
                    {
                        ServerId = serverSection.Key,
                        Name = serverSection.GetValue<string>("Name") ?? serverSection.Key,
                        Endpoint = serverSection.GetValue<string>("Endpoint") ?? string.Empty,
                        Timeout = TimeSpan.FromSeconds(serverSection.GetValue<int>("Timeout", 30)),
                        Enabled = serverSection.GetValue<bool>("Enabled", true)
                    };

                    // 读取参数
                    var parametersSection = serverSection.GetSection("Parameters");
                    if (parametersSection.Exists())
                    {
                        foreach (var param in parametersSection.GetChildren())
                        {
                            serverConfig.Parameters[param.Key] = param.Value ?? string.Empty;
                        }
                    }

                    if (serverConfig.Enabled && !string.IsNullOrEmpty(serverConfig.Endpoint))
                    {
                        _mcpServers[serverConfig.ServerId] = serverConfig;
                        _logger.LogInformation("MCP server configured: {ServerId} - {Name}",
                            serverConfig.ServerId, serverConfig.Name);
                    }
                }
            }

            // 添加一些示例MCP服务器配置
            if (!_mcpServers.Any())
            {
                _mcpServers["weather_server"] = new McpServerConfig
                {
                    ServerId = "weather_server",
                    Name = "天气服务",
                    Endpoint = "http://localhost:8080/mcp",
                    Enabled = false // 默认禁用，需要实际的服务器
                };

                _mcpServers["file_server"] = new McpServerConfig
                {
                    ServerId = "file_server",
                    Name = "文件服务",
                    Endpoint = "http://localhost:8081/mcp",
                    Enabled = false // 默认禁用，需要实际的服务器
                };
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to initialize MCP servers");
        }
    }

    private async Task RefreshMcpToolsAsync()
    {
        foreach (var server in _mcpServers.Values.Where(s => s.Enabled))
        {
            try
            {
                await LoadToolsFromServerAsync(server);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "Failed to load tools from MCP server: {ServerId}", server.ServerId);
            }
        }
    }

    private async Task LoadToolsFromServerAsync(McpServerConfig serverConfig)
    {
        try
        {
            using var httpClient = _httpClientFactory.CreateClient();
            httpClient.Timeout = serverConfig.Timeout;

            var request = new
            {
                jsonrpc = "2.0",
                id = Guid.NewGuid().ToString(),
                method = "tools/list",
                parameters = new { }
            };

            var response = await httpClient.PostAsJsonAsync(serverConfig.Endpoint, request);
            response.EnsureSuccessStatusCode();

            var responseContent = await response.Content.ReadFromJsonAsync<JsonElement>();

            if (responseContent.TryGetProperty("result", out var resultElement) &&
                resultElement.TryGetProperty("tools", out var toolsElement))
            {
                foreach (var toolElement in toolsElement.EnumerateArray())
                {
                    var toolDef = ParseMcpToolDefinition(toolElement, serverConfig);
                    if (toolDef != null)
                    {
                        _mcpTools[toolDef.Id] = toolDef;
                    }
                }
            }

            _logger.LogDebug("Loaded {Count} tools from MCP server: {ServerId}",
                toolsElement.GetArrayLength(), serverConfig.ServerId);
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Failed to load tools from MCP server: {ServerId}", serverConfig.ServerId);

            // 添加一些示例工具，以便演示
            if (serverConfig.ServerId == "weather_server")
            {
                _mcpTools["weather_query"] = new ToolDefinition
                {
                    Id = "weather_query",
                    Name = "天气查询",
                    Description = "查询指定城市的天气信息",
                    Type = ToolType.McpServer,
                    Parameters = new Dictionary<string, ToolParameter>
                    {
                        ["city"] = new ToolParameter
                        {
                            Name = "city",
                            Type = "string",
                            Description = "城市名称",
                            Required = true
                        },
                        ["units"] = new ToolParameter
                        {
                            Name = "units",
                            Type = "string",
                            Description = "温度单位：celsius, fahrenheit",
                            Required = false,
                            DefaultValue = "celsius",
                            EnumValues = new List<string> { "celsius", "fahrenheit" }
                        }
                    },
                    Configuration = new Dictionary<string, object>
                    {
                        ["serverId"] = serverConfig.ServerId
                    },
                    Tags = new List<string> { "weather", "mcp", "external" }
                };
            }
        }
    }

    private ToolDefinition? ParseMcpToolDefinition(JsonElement toolElement, McpServerConfig serverConfig)
    {
        try
        {
            var id = toolElement.GetProperty("name").GetString();
            var name = toolElement.GetProperty("name").GetString();
            var description = toolElement.GetProperty("description").GetString();

            if (string.IsNullOrEmpty(id)) return null;

            var toolDef = new ToolDefinition
            {
                Id = id,
                Name = name ?? id,
                Description = description ?? string.Empty,
                Type = ToolType.McpServer,
                Configuration = new Dictionary<string, object>
                {
                    ["serverId"] = serverConfig.ServerId,
                    ["serverName"] = serverConfig.Name,
                    ["endpoint"] = serverConfig.Endpoint
                },
                Tags = new List<string> { "mcp", serverConfig.ServerId, "external" }
            };

            // 解析参数
            if (toolElement.TryGetProperty("inputSchema", out var schemaElement))
            {
                ParseMcpToolParameters(schemaElement, toolDef);
            }

            return toolDef;
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Failed to parse MCP tool definition");
            return null;
        }
    }

    private void ParseMcpToolParameters(JsonElement schemaElement, ToolDefinition toolDef)
    {
        try
        {
            if (schemaElement.TryGetProperty("properties", out var propertiesElement))
            {
                foreach (var prop in propertiesElement.EnumerateObject())
                {
                    var paramDef = new ToolParameter
                    {
                        Name = prop.Name,
                        Type = prop.Value.TryGetProperty("type", out var typeElement)
                            ? typeElement.GetString() ?? "string"
                            : "string",
                        Description = prop.Value.TryGetProperty("description", out var descElement)
                            ? descElement.GetString() ?? string.Empty
                            : string.Empty
                    };

                    toolDef.Parameters[prop.Name] = paramDef;
                }
            }

            // 检查必需参数
            if (schemaElement.TryGetProperty("required", out var requiredElement))
            {
                foreach (var requiredProp in requiredElement.EnumerateArray())
                {
                    var propName = requiredProp.GetString();
                    if (!string.IsNullOrEmpty(propName) && toolDef.Parameters.ContainsKey(propName))
                    {
                        toolDef.Parameters[propName].Required = true;
                    }
                }
            }
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Failed to parse MCP tool parameters for tool: {ToolId}", toolDef.Id);
        }
    }

    private async Task<(bool Success, object? Data, string? Error)> CallMcpToolAsync(
        McpServerConfig serverConfig,
        ToolDefinition toolDef,
        ToolExecutionRequest request)
    {
        try
        {
            using var httpClient = _httpClientFactory.CreateClient();
            httpClient.Timeout = request.Timeout ?? serverConfig.Timeout;

            var mcpRequest = new
            {
                jsonrpc = "2.0",
                id = Guid.NewGuid().ToString(),
                method = "tools/call",
                parameters = new
                {
                    name = toolDef.Id,
                    arguments = request.Parameters
                }
            };

            var response = await httpClient.PostAsJsonAsync(serverConfig.Endpoint, mcpRequest);
            var responseContent = await response.Content.ReadAsStringAsync();

            if (!response.IsSuccessStatusCode)
            {
                return (false, null, $"MCP server returned status {response.StatusCode}: {responseContent}");
            }

            using var jsonDoc = JsonDocument.Parse(responseContent);
            var root = jsonDoc.RootElement;

            if (root.TryGetProperty("error", out var errorElement))
            {
                var errorMessage = errorElement.TryGetProperty("message", out var msgElement)
                    ? msgElement.GetString()
                    : "MCP server returned an error";
                return (false, null, $"MCP error: {errorMessage}");
            }

            if (root.TryGetProperty("result", out var resultElement))
            {
                return (true, resultElement, null);
            }

            return (false, null, "Invalid MCP response format");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to call MCP tool: {ToolId} on server: {ServerId}",
                toolDef.Id, serverConfig.ServerId);
            return (false, null, ex.Message);
        }
    }

    private bool ValidateParameterType(object? value, string expectedType)
    {
        if (value == null) return true;

        return expectedType.ToLower() switch
        {
            "string" => value is string,
            "number" => value is int or double or decimal or float,
            "boolean" => value is bool,
            "array" => value is Array || value is List<object>,
            "object" => value is Dictionary<string, object>,
            _ => true
        };
    }
}